#ifndef CONFIGELEMENT_H_INCLUDED
#define CONFIGELEMENT_H_INCLUDED

#include "tinyxml/tinyxml.h"
#include "utils.h"



#ifdef _SCRIPTLOADER_LIB
#   ifdef OPENNANO_EXPORT
#       undef OPENNANO_EXPORT
#   endif
#   define OPENNANO_EXPORT  OPENNANO_EXPORT_DECL
#else
#   define OPENNANO_EXPORT  OPENNANO_IMPORT_DECL
#endif

#include "utils/Factory.h"

#define UNKNOWN_ELEMENT  "unknown"

namespace OpenNano
{

    class ScriptLoader;
    class UnknownElement;
    typedef std::map<std::string, UnknownElement *> UnknownElementsList;
    typedef std::map<std::string, std::string>  UnknownAttributesList;

    class OPENNANO_EXPORT ConfigElement
    {
        private:
            TiXmlElement * el;
            UnknownElementsList _children;
            UnknownAttributesList _attribs;
            std::string _text;
            bool _processed;

            log4cplus::Logger logger;

        protected:
            ConfigElement(TiXmlElement * element);

            TiXmlElement * getTiXmlElement();
            void unknownAttributeFound(TiXmlAttribute * unknown);
            void unknownElementFound(TiXmlElement * unknown);
            void unknownTextFound(const char * text);

            virtual void attributeFound(TiXmlAttribute * attribute ) = 0;
            virtual void childElementFound( TiXmlElement * childElement ) = 0;
            virtual void textFound(const char * text)=0;
            virtual bool postConfiguration() = 0;
            virtual void init() = 0;

        public:
            bool process ();
            virtual ~ConfigElement();

            UnknownElement * getUnknownElement(const std::string& name);
            const UnknownElementsList& getUnknownElements() const;

            bool getUnknownAttribute(const std::string& name, std::string &value);
            const UnknownAttributesList& getUnknownAttributes() const;

            const std::string & getUnknownText() const;


        friend class ScriptLoader;
   //     friend class ConfigElementCreator;
    };

#define DECLARE_OBJECT_FACTORY( ObjectClass ) \
public: \
        \
        friend class ConfigElementCreatorT< ObjectClass > ; \
        \
        static std::string CLASS_ID ;                                    \
        \
        static const bool REGISTERED_IN_OBJECT_FACTORY ; \
        \
        private:\
            \
            log4cplus::Logger logger;\
        protected: \
        \
            ObjectClass( TiXmlElement * element ) ; \
        public: \
            virtual ~ObjectClass()

#define REGISTER_OBJECT_FACTORY( ObjectClass, ClassID ) \
std::string ObjectClass::CLASS_ID( ClassID );\
const bool ObjectClass::REGISTERED_IN_OBJECT_FACTORY(ConfigElementFactory::getInstance().registerCreator< ConfigElementCreatorT< ObjectClass > >( ClassID ) )


class ConfigElementCreator
{
    public:
        virtual ~ConfigElementCreator(){}
        virtual ConfigElement* operator() (TiXmlElement * element) const
        {
            //NOTE_TO_SELF
            //NOTIFY_ERROR
            return 0;
        }
};

template <class T>
class ConfigElementCreatorT :
           public ConfigElementCreator
{
    public:
        virtual ~ConfigElementCreatorT(){}
        ConfigElement* operator() (TiXmlElement * element) const
        {
            T * confEl = new T(element);
            if (confEl) confEl->init();
            //ConfigElement * configEl = new T(element);
//            if (configEl) configEl->init();
            return (ConfigElement *)confEl;
        }
};


    typedef Singleton< FactoryT< ConfigElementCreator > > ConfigElementFactory;

    typedef std::map< std::string, ConfigElement *> ConfigurationMap;
    typedef Singleton< ConfigurationMap > ConfigMap;
    typedef std::pair< std::string, ConfigElement* > CM_Entry;
    typedef std::multimap< std::string, ConfigElement* >::iterator CM_Iterator;
    typedef std::multimap< std::string, ConfigElement* >::const_iterator CM_Const_Iterator;


}


#endif // CONFIGELEMENT_H_INCLUDED
